package vn.com.aptech.msh.business;

import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import vn.com.aptech.msh.criteria.PayingGuestCriteria;
import vn.com.aptech.msh.criteria.RentalBasisCriteria;
import vn.com.aptech.msh.criteria.SellingHouseCriteria;
import vn.com.aptech.msh.entities.Advertising;
import vn.com.aptech.msh.entities.HouseType;
import vn.com.aptech.msh.entities.PayingGuestAccommodation;
import vn.com.aptech.msh.entities.RentalBasisAccommodation;
import vn.com.aptech.msh.entities.SellingHouse;

/**
 *
 * @author trietto
 */
@Stateless
public class EstateBean implements IEstateBean {

    @PersistenceContext(unitName = "MySweetHome-ejbPU")
    private EntityManager em;

    protected EntityManager getEntityManager() {
        return em;
    }

    public EstateBean() {
        //super(User.class);
    }

    @Override
    public List<HouseType> getHouseTypes() {
        javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        cq.select(cq.from(HouseType.class));
        return getEntityManager().createQuery(cq).getResultList();
    }

    @Override
    public Advertising advertiseSellingHouse(Advertising advert) {
        SellingHouse child = advert.getSellingHouse();
        advert.setSellingHouse(null);
        em.persist(advert);
        em.flush();
        child.setAdvertisingID(advert.getAdvertisingID());
        em.persist(child);
        em.flush();
        advert.setSellingHouse(child);
        return advert;
    }

    @Override
    public Advertising advertiseRentalBasis(Advertising advert) {
        RentalBasisAccommodation child = advert.getRentalBasisAccommodation();
        advert.setRentalBasisAccommodation(null);
        em.persist(advert);
        em.flush();
        child.setAdvertisingID(advert.getAdvertisingID());
        em.persist(child);
        em.flush();
        advert.setRentalBasisAccommodation(child);
        return advert;
    }

    @Override
    public Advertising advertisePayingGuest(Advertising advert) {
        PayingGuestAccommodation child = advert.getPayingGuestAccommodation();
        advert.setPayingGuestAccommodation(null);
        em.persist(advert);
        em.flush();
        child.setAdvertisingID(advert.getAdvertisingID());
        em.persist(child);
        em.flush();
        advert.setPayingGuestAccommodation(child);
        return advert;
    }

    @Override
    public List<Advertising> searchSellingHouse(SellingHouseCriteria criteria) {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Advertising> cq = cb.createQuery(Advertising.class);
        Root<Advertising> adv = cq.from(Advertising.class);
        Join<Advertising, SellingHouse> join = adv.join("sellingHouse");
        cq.select(adv);
        cq.orderBy(cb.desc(adv.get("postDate")));
        if (criteria != null) {
            criteria.finish();

            Predicate p = cb.like(join.<String>get("city"), criteria.getCity());
            p = cb.and(p, cb.like(join.<String>get("location"), criteria.getLocation()));
            p = cb.and(p, cb.between(join.<Double>get("price"), criteria.getPriceMin(), criteria.getPriceMax()));
            p = cb.and(p, cb.between(join.<Double>get("squareFootage"), criteria.getSquareFootageMin(), criteria.getSquareFootageMax()));
            p = cb.and(p, cb.between(join.<Integer>get("noOfBedrooms"), criteria.getNoBedroomsMin(), criteria.getNoBedroomsMax()));
            p = cb.and(p, cb.between(join.<Integer>get("noOfBathrooms"), criteria.getNoBathroomsMin(), criteria.getNoBathroomsMax()));

            HouseType houseType = criteria.getHouseType();
            if (houseType != null && houseType.getHouseTypeID() != null && houseType.getHouseTypeID() != 0) {
                p = cb.and(p, cb.equal(join.<HouseType>get("houseType"), houseType));
            }
            cq.where(p);
        }
        TypedQuery<Advertising> query = em.createQuery(cq);
        return query.getResultList();
    }

    @Override
    public List<Advertising> searchRentalBasis(RentalBasisCriteria criteria) {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Advertising> cq = cb.createQuery(Advertising.class);
        Root<Advertising> adv = cq.from(Advertising.class);
        Join<Advertising, RentalBasisAccommodation> join = adv.join("rentalBasisAccommodation");
        cq.select(adv);
        cq.orderBy(cb.desc(adv.get("postDate")));
        if (criteria != null) {
            criteria.finish();

            Predicate p = cb.like(join.<String>get("city"), criteria.getCity());
            p = cb.and(p, cb.like(join.<String>get("location"), criteria.getLocation()));
            p = cb.and(p, cb.between(join.<Double>get("deposit"), criteria.getDepositMin(), criteria.getDepositMax()));
            p = cb.and(p, cb.between(join.<Double>get("rent"), criteria.getRentMin(), criteria.getRentMax()));
            p = cb.and(p, cb.between(join.<Integer>get("noOfBedrooms"), criteria.getNoBedroomsMin(), criteria.getNoBedroomsMax()));
            p = cb.and(p, cb.between(join.<Integer>get("noOfBathrooms"), criteria.getNoBathroomsMin(), criteria.getNoBathroomsMax()));
            cq.where(p);
        }
        TypedQuery<Advertising> query = em.createQuery(cq);
        return query.getResultList();
    }

    @Override
    public List<Advertising> searchPayingGuest(PayingGuestCriteria criteria) {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Advertising> cq = cb.createQuery(Advertising.class);
        Root<Advertising> adv = cq.from(Advertising.class);
        Join<Advertising, PayingGuestAccommodation> join = adv.join("payingGuestAccommodation");
        cq.select(adv);
        cq.orderBy(cb.desc(adv.get("postDate")));
        if (criteria != null) {
            criteria.finish();

            Predicate p = cb.like(join.<String>get("city"), criteria.getCity());
            p = cb.and(p, cb.like(join.<String>get("location"), criteria.getLocation()));
            p = cb.and(p, cb.between(join.<Double>get("deposit"), criteria.getDepositMin(), criteria.getDepositMax()));
            p = cb.and(p, cb.between(join.<Double>get("rent"), criteria.getRentMin(), criteria.getRentMax()));
            cq.where(p);
        }
        TypedQuery<Advertising> query = em.createQuery(cq);
        return query.getResultList();
    }

    @Override
    public int getAdvertisementsCount() {
        Query query = em.createQuery("SELECT COUNT(adv.advertisingID) FROM Advertising adv");
        Number countResult = (Number) query.getSingleResult();
        return countResult.intValue();
    }

    @Override
    public List<Advertising> getLatestAdvertisements(int top) {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Advertising> cq = cb.createQuery(Advertising.class);
        Root<Advertising> adv = cq.from(Advertising.class);
        cq.select(adv);
        cq.orderBy(cb.desc(adv.get("postDate")));

        TypedQuery<Advertising> query = em.createQuery(cq);
        query.setMaxResults(top);
        return query.getResultList();
    }

    @Override
    public Advertising findAdvertisingById(int id) {
        return getEntityManager().find(Advertising.class, id);
    }

    @Override
    public List<Advertising> getFeaturedAdvertisements(int top) {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Advertising> cq = cb.createQuery(Advertising.class);
        Root<Advertising> adv = cq.from(Advertising.class);
        cq.select(adv);
        cq.orderBy(cb.desc(adv.get("priority")), cb.desc(adv.get("postDate")));
        cq.where(cb.and(cb.isNotNull(adv.get("imagePath")), cb.notEqual(adv.get("imagePath"), "")));

        TypedQuery<Advertising> query = em.createQuery(cq);
        query.setMaxResults(top);
        return query.getResultList();
    }
}
